home *** CD-ROM | disk | FTP | other *** search
/ Aminet 21 / Aminet 21 (1997)(GTI - Schatztruhe)[!][Oct 1997].iso / Aminet / mus / midi / splitter.lha / splitter.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-19  |  24.8 KB  |  998 lines

  1. /*
  2.     Splitter: A Bars & Pipes Accessory for splitting a track into
  3.     many tracks, according to a note map as used
  4.     by the Pattern Tool for drum kits.
  5.  
  6.     Copyright (C) 1997 Richard Hagen
  7.         This code is released into the Public Domain, and may be freely
  8.     distributed in its original form.
  9.  
  10.     It is supplied ``as is'', and comes with no warranty.
  11.     This program code was released because it might be useful as a
  12.     starting point for other programmers. However, if any damage arises
  13.     from its use, the original author will not be held liable.
  14.  
  15.     You are free to use and modify this code to your heart's content,
  16.     provided you acknowledge me as the original author in any code
  17.     that you might distribute which is based largely on this code.
  18.  
  19.     I acknowledge that the design of this accessory is influenced
  20.     strongly by the example code supplied with the Rules for Tools
  21.     package. However, I have made substantial contributions of my
  22.     own.
  23.  
  24.     Richard Hagen
  25.     richard@it.uq.edu.au
  26.     August 1997
  27.  
  28.     History:
  29.         Version 1.1: 19 August 1997
  30.         Added ``Clear Note Map'' button.
  31.         Tidied up some silly code.
  32.         Version 1.0: 12 August 1997
  33.         Initial Release.
  34. */
  35.  
  36. #include <intuition/intuition.h>
  37. #include <libraries/dos.h>
  38. #include <libraries/gadtools.h>
  39. #include <exec/memory.h>
  40. #include <stdarg.h>
  41. #include <string.h>
  42. #include <stddef.h>
  43. #include <stdio.h>
  44.  
  45. #include "bars.h"
  46.  
  47. #include "myheader.h"
  48.  
  49. /* -------------------------------------------------------------------- */
  50. /*                 ICON IMAGERY                */
  51. /* -------------------------------------------------------------------- */
  52.  
  53. /* I did these by hand to get the feel for what goes into a bitmap image.
  54.    I really don't want to do it again! Can anyone point me at a good tool
  55.    for doing the design for these sorts of things? */
  56.  
  57. /* Normal icon. */
  58. static const __chip UWORD splitter_image_data[] = {
  59.   /* Plane 0 */
  60.   0x0, 0x0, 0x0,
  61.   0x0, 0x0, 0x0,
  62.   0x0, 0x0, 0x0,
  63.   0x0, 0x0, 0x0,
  64.   0x0, 0x0, 0x0,
  65.   0x0, 0x0, 0x0,
  66.   0x0, 0x0, 0x0,
  67.   0x0, 0x0, 0x0,
  68.   0x0, 0x0, 0x0,
  69.   0x0, 0x0, 0x0,
  70.   0x0, 0x0, 0x0,
  71.   0x0, 0x0, 0x0,
  72.   0x7fff, 0xffff, 0xe000,
  73.   0x7fff, 0xffff, 0xe000,
  74.   0x38f0, 0x0c00, 0x0,
  75.   0x38f0, 0x0c00, 0x0,
  76.   0x0401, 0x8270, 0x0,
  77.   0x0401, 0x8270, 0x0,
  78.   0x0303, 0xc103, 0x0,
  79.   0x0303, 0xc103, 0x0,
  80.   0x7fff, 0xffff, 0xe000,
  81.   0x7fff, 0xffff, 0xe000,
  82.   0x0, 0x0, 0x0,
  83.   0x0, 0x0, 0x0,
  84.   0x0, 0x0, 0x0,
  85.   0x0, 0x0, 0x0,
  86.   0x0, 0x0, 0x0,
  87.   0x0, 0x0, 0x0,
  88.   0x0, 0x0, 0x0,
  89.   0x0, 0x0, 0x0,
  90.   0x0, 0x0, 0x0,
  91.   0x0, 0x0, 0x0,
  92.   0x0, 0x0, 0x0,
  93.   0x0, 0x0, 0x0,
  94.  
  95.   /* Plane 1 */
  96.   0x0, 0x0, 0x0,
  97.   0x0, 0x0, 0x0,
  98.   0x0, 0x0, 0x0,
  99.   0x0, 0x0, 0x0,
  100.   0x0, 0x0, 0x0,
  101.   0x0, 0x0, 0x0,
  102.   0x0, 0x0, 0x0,
  103.   0x0, 0x0, 0x0,
  104.   0x0, 0x0, 0x0,
  105.   0x0, 0x0, 0x0,
  106.   0x0, 0x0, 0x0,
  107.   0x0, 0x0, 0x0,
  108.   0x7fff, 0xffff, 0xe000,
  109.   0x7fff, 0xffff, 0xe000,
  110.   0x2108, 0x4210, 0x8000,
  111.   0x2108, 0x4210, 0x8000,
  112.   0x2108, 0x4210, 0x8000,
  113.   0x2108, 0x4210, 0x8000,
  114.   0x2108, 0x4210, 0x8000,
  115.   0x2108, 0x4210, 0x8000,
  116.   0x7fff, 0xffff, 0xe000,
  117.   0x7fff, 0xffff, 0xe000,
  118.   0x0, 0x0, 0x0,
  119.   0x0, 0x0, 0x0,
  120.   0x0, 0x0, 0x0,
  121.   0x0, 0x0, 0x0,
  122.   0x0, 0x0, 0x0,
  123.   0x0, 0x0, 0x0,
  124.   0x0, 0x0, 0x0,
  125.   0x0, 0x0, 0x0,
  126.   0x0, 0x0, 0x0,
  127.   0x0, 0x0, 0x0,
  128.   0x0, 0x0, 0x0,
  129.   0x0, 0x0, 0x0,
  130.  
  131.   /* Plane #2 */
  132.   0x0, 0x0, 0x0,
  133.   0x0, 0x0, 0x0,
  134.   0x0, 0x0, 0x0,
  135.   0x0, 0x0, 0x0,
  136.   0x0, 0x0, 0x0,
  137.   0x0, 0x0, 0x0,
  138.   0x0, 0x0, 0x0,
  139.   0x0, 0x0, 0x0,
  140.   0x0, 0x0, 0x0,
  141.   0x0, 0x0, 0x0,
  142.   0x0, 0x0, 0x0,
  143.   0x0, 0x0, 0x0,
  144.   0x0, 0x0, 0x0,
  145.   0x0, 0x0, 0x0,
  146.   0x0, 0x0, 0x0,
  147.   0x0, 0x0, 0x0,
  148.   0x0, 0x0, 0x0,
  149.   0x0, 0x0, 0x0,
  150.   0x0, 0x0, 0x0,
  151.   0x0, 0x0, 0x0,
  152.   0x0, 0x0, 0x0,
  153.   0x0, 0x0, 0x0,
  154.   0x0, 0x0, 0x0,
  155.   0x0, 0x0, 0x0,
  156.   0x0, 0x0, 0x0,
  157.   0x0, 0x0, 0x0,
  158.   0x0, 0x0, 0x0,
  159.   0x0, 0x0, 0x0,
  160.   0x0, 0x0, 0x0,
  161.   0x0, 0x0, 0x0,
  162.   0x0, 0x0, 0x0,
  163.   0x0, 0x0, 0x0,
  164.   0x0, 0x0, 0x0,
  165.   0x0, 0x0, 0x0,
  166. };
  167.  
  168. static const struct Image splitter_image = {
  169.   0, 0,
  170.   48, 34, 3,
  171.   splitter_image_data,
  172.   0x1f, 0x00,
  173.   NULL
  174. };
  175.  
  176. /* Selected icon. */
  177. static const __chip UWORD splitter_onimage_data[] =  {
  178.   /* Plane 0 */
  179.   0x0, 0x0, 0x0,
  180.   0x0, 0x0, 0x0,
  181.   0x0, 0x0, 0x0,
  182.   0x0, 0x0, 0x0,
  183.   0x7fff, 0xffff, 0xe000,
  184.   0x7fff, 0xffff, 0xe000,
  185.   0x38f0, 0x0c00, 0x0,
  186.   0x38f0, 0x0c00, 0x0,
  187.   0x7fff, 0xffff, 0xe000,
  188.   0x7fff, 0xffff, 0xe000,
  189.   0x0, 0x0, 0x0,
  190.   0x0, 0x0, 0x0,
  191.   0x0, 0x0, 0x0,
  192.   0x0, 0x0, 0x0,
  193.   0x7fff, 0xffff, 0xe000,
  194.   0x7fff, 0xffff, 0xe000,
  195.   0x0401, 0x8270, 0x0,
  196.   0x0401, 0x8270, 0x0,
  197.   0x7fff, 0xffff, 0xe000,
  198.   0x7fff, 0xffff, 0xe000,
  199.   0x0, 0x0, 0x0,
  200.   0x0, 0x0, 0x0,
  201.   0x0, 0x0, 0x0,
  202.   0x0, 0x0, 0x0,
  203.   0x7fff, 0xffff, 0xe000,
  204.   0x7fff, 0xffff, 0xe000,
  205.   0x0303, 0xc103, 0x0,
  206.   0x0303, 0xc103, 0x0,
  207.   0x7fff, 0xffff, 0xe000,
  208.   0x7fff, 0xffff, 0xe000,
  209.   0x0, 0x0, 0x0,
  210.   0x0, 0x0, 0x0,
  211.   0x0, 0x0, 0x0,
  212.   0x0, 0x0, 0x0,
  213.   
  214.   /* Plane 1 */
  215.   0x0, 0x0, 0x0,
  216.   0x0, 0x0, 0x0,
  217.   0x0, 0x0, 0x0,
  218.   0x0, 0x0, 0x0,
  219.   0x0, 0x0, 0x0,
  220.   0x0, 0x0, 0x0,
  221.   0x0, 0x0, 0x0,
  222.   0x0, 0x0, 0x0,
  223.   0x0, 0x0, 0x0,
  224.   0x0, 0x0, 0x0,
  225.   0x0, 0x0, 0x0,
  226.   0x0, 0x0, 0x0,
  227.   0x0, 0x0, 0x0,
  228.   0x0, 0x0, 0x0,
  229.   0x0, 0x0, 0x0,
  230.   0x0, 0x0, 0x0,
  231.   0x0, 0x0, 0x0,
  232.   0x0, 0x0, 0x0,
  233.   0x0, 0x0, 0x0,
  234.   0x0, 0x0, 0x0,
  235.   0x0, 0x0, 0x0,
  236.   0x0, 0x0, 0x0,
  237.   0x0, 0x0, 0x0,
  238.   0x0, 0x0, 0x0,
  239.   0x0, 0x0, 0x0,
  240.   0x0, 0x0, 0x0,
  241.   0x0, 0x0, 0x0,
  242.   0x0, 0x0, 0x0,
  243.   0x0, 0x0, 0x0,
  244.   0x0, 0x0, 0x0,
  245.   0x0, 0x0, 0x0,
  246.   0x0, 0x0, 0x0,
  247.   0x0, 0x0, 0x0,
  248.   0x0, 0x0, 0x0,
  249.  
  250.   /* Plane #2 */
  251.   0x0, 0x0, 0x0,
  252.   0x0, 0x0, 0x0,
  253.   0x0, 0x0, 0x0,
  254.   0x0, 0x0, 0x0,
  255.   0x7fff, 0xffff, 0xe000,
  256.   0x7fff, 0xffff, 0xe000,
  257.   0x2108, 0x4210, 0x8000,
  258.   0x2108, 0x4210, 0x8000,
  259.   0x7fff, 0xffff, 0xe000,
  260.   0x7fff, 0xffff, 0xe000,
  261.   0x0, 0x0, 0x0,
  262.   0x0, 0x0, 0x0,
  263.   0x0, 0x0, 0x0,
  264.   0x0, 0x0, 0x0,
  265.   0x7fff, 0xffff, 0xe000,
  266.   0x7fff, 0xffff, 0xe000,
  267.   0x2108, 0x4210, 0x8000,
  268.   0x2108, 0x4210, 0x8000,
  269.   0x7fff, 0xffff, 0xe000,
  270.   0x7fff, 0xffff, 0xe000,
  271.   0x0, 0x0, 0x0,
  272.   0x0, 0x0, 0x0,
  273.   0x0, 0x0, 0x0,
  274.   0x0, 0x0, 0x0,
  275.   0x7fff, 0xffff, 0xe000,
  276.   0x7fff, 0xffff, 0xe000,
  277.   0x2108, 0x4210, 0x8000,
  278.   0x2108, 0x4210, 0x8000,
  279.   0x7fff, 0xffff, 0xe000,
  280.   0x7fff, 0xffff, 0xe000,
  281.   0x0, 0x0, 0x0,
  282.   0x0, 0x0, 0x0,
  283.   0x0, 0x0, 0x0,
  284.   0x0, 0x0, 0x0,
  285. };
  286.  
  287. static const struct Image splitter_onimage = {
  288.   1, 0,
  289.   48, 34, 3,
  290.   splitter_onimage_data,
  291.   0x1f, 0x00,
  292.   NULL
  293. };
  294.  
  295. /* Global Bars & Pipes functions pointer. */
  296. extern struct Functions *functions;
  297.  
  298. /* Title for error requester. */
  299. static const char *error_title = "Splitter error";
  300.  
  301. /* Puts up a simple requester for relaying error messages. */
  302. static void
  303. accessory_error(struct Window *window,    /* Window to open requester in. */
  304.         const char *s)        /* String to put in the requester. */
  305. {
  306.   const struct EasyStruct easy = {
  307.     sizeof(struct EasyStruct),
  308.     0,
  309.     error_title,
  310.     s,
  311.     "OK"
  312.   };
  313.  
  314.   (void) EasyRequest(window, &easy, NULL);
  315. }
  316.  
  317. /* -------------------------------------------------------------------- */
  318. /*                 Note Maps                */
  319. /* -------------------------------------------------------------------- */
  320.  
  321. /* Note maps are created by the Pattern tool when you edit a drum
  322.    kit. Have a bit of a play with the drum map editing facility
  323.    to get a feel for what data needs to be stored for a note map.
  324.    
  325.    The file containing the note map has the following format:
  326.  
  327.    Description        Size        Value        Comment
  328.  
  329.    File ID        4 Bytes        "NTMP"
  330.    Length of File    4 Bytes                File length - 8
  331.    Offset to note data    4 Bytes
  332.    Pointer to note data    4 Bytes                Ignore this
  333.    ?Spare byte?        1 Byte        0x00        ?
  334.    MIDI Note to ID Map    128 Bytes
  335.    ID to MIDI Note Map    128 Bytes
  336.    ID to position Map    128 Bytes
  337.    ?Spare Byte?        1 Byte        0x00        ?
  338.    ?Map ID?        4 Bytes        "DRUM"        ?Different maps?
  339.    Length of map    4 Bytes
  340.    Length of map entry    4 Bytes        0x00000018
  341.    Map entries -
  342.     Pointer to next    4 Bytes                0 if last entry,
  343.                             otherwise, ignore
  344.     Note name    15 Bytes            0 in last byte
  345.     Note ID        1 Byte
  346.     MIDI note    1 Byte
  347.     Note position    1 Byte
  348.     Flags        4 Bytes                0x00000001 == selected
  349.                             ?other flags?
  350.  
  351.   If anyone can help me out with the things marked ``?'', I'd really
  352.   appreciate it! */
  353.  
  354. /* Length of note name as stored in note map file. */
  355. #define NOTE_NAME_LEN     15
  356.  
  357. /* Format of records stored in the note map file. */
  358. struct NotemapFileEntry {
  359.   char name[NOTE_NAME_LEN];
  360.   UBYTE id;
  361.   UBYTE note;
  362.   UBYTE pos;
  363.   UWORD flags;
  364. };
  365.  
  366. /* Strings for holding note names. */
  367. typedef char *Notemap[MIDI_NOTE_NUM];    /* Indexed by note number. */
  368.  
  369. /* My accessory needs to remember a notemap, so I've bundled the two
  370.    things together. */
  371. struct Splitter {
  372.   struct Accessory accessory;
  373.   Notemap *notemap;
  374. };
  375.  
  376. /* My accessory. */
  377. struct Splitter splitter;
  378.  
  379. /* Allocates, initialises and returns a new notemap.
  380.    If something goes wrong, it returns NULL. */
  381. static Notemap *
  382. notemap_new(void)
  383. {
  384.   register unsigned int i;
  385.  
  386.   /* Attempt the allocation and check for failure. */
  387.   Notemap *notemap =
  388.     (Notemap *)(*functions->myalloc)(sizeof(Notemap), MEMF_CLEAR);
  389.   if (notemap == (Notemap *) NULL)
  390.     {
  391.       /* Allocation failed */
  392.       return (Notemap *) NULL;
  393.     }
  394.   
  395.   /* Carefully initialise all the strings in the notemap. */
  396.   for (i = 0; i < MIDI_NOTE_NUM; i++)
  397.     {
  398.       (*notemap)[i] = (char *) NULL;
  399.     }
  400.  
  401.   return notemap;
  402. }
  403.  
  404. /* Frees the strings in a notemap. */
  405. static void
  406. notemap_delete_entries(Notemap *notemap)
  407. {
  408.   register unsigned int i;
  409.  
  410.   /* Ensure that we've been given something to delete. */
  411.   if (notemap != (Notemap *) NULL)
  412.     {
  413.       /* For each string in the notemap. */
  414.       for (i = 0; i < MIDI_NOTE_NUM; i++)
  415.         {
  416.       /* Check to see if we have to do anything. */
  417.           if ((*notemap)[i] != (char *) NULL)
  418.             {
  419.           /* Free the storage and make the pointer difficult to reuse. */
  420.               (*functions->myfree)((*notemap)[i],
  421.                    strlen((*notemap)[i]) + 1);
  422.               (*notemap)[i] = (char *) NULL;
  423.         }
  424.         }
  425.     }
  426. }
  427.  
  428. /* Frees an entire notemap structure (including the strings). */
  429. static void
  430. notemap_delete(Notemap *notemap)
  431. {
  432.   /* Ensure that we've been given something to delete. */
  433.   if (notemap != (Notemap *) NULL)
  434.     {
  435.       /* Delete the entries, and free the storage for the notemap. */
  436.       notemap_delete_entries(notemap);
  437.       (*functions->myfree)(notemap, sizeof(Notemap));
  438.     }
  439. }
  440.  
  441. /* Load a notemap from the file. If an error occurs, an incomplete
  442.    notemap isn't deleted. */
  443. static void
  444. notemap_load(long file,        /* Open file. */
  445.          Notemap *notemap)    /* Notemap to fill in. */
  446. {
  447.   char file_id[ID_LEN];        /* File ID. */
  448.   ULONG offset = 0;        /* Offset to name map entries. */
  449.   ULONG next = 0;        /* Next pointer. */
  450.  
  451.   /* Ensure that the file id is one for a note map. */
  452.   if ((*functions->fastread)(file, file_id, ID_LEN) < ID_LEN)
  453.     {
  454.       /* Failed to read the correct number of bytes for the file id. */
  455.       return;
  456.     }
  457.   if (strncmp(file_id, "NTMP", ID_LEN) != 0)
  458.     {
  459.       /* Incorrect id */
  460.       return;
  461.     }
  462.  
  463.   /* Skip over the file length */
  464.   if ((*functions->fastseek)(file, sizeof(ULONG), OFFSET_CURRENT) < 0)
  465.     {
  466.       /* Seek failed */
  467.       return;
  468.     }
  469.  
  470.   /* Read the offset for the note map entry data. */
  471.   if ((*functions->fastread)(file, (UBYTE *)&offset, sizeof(offset)) < sizeof(offset))
  472.     {
  473.       /* Failed to read the correct number of bytes for the offset. */
  474.       return;
  475.     }
  476.  
  477.   /* Skip to the note map entries. Don't bother checking the
  478.      map id or record length. */
  479.   if ((*functions->fastseek)(file, offset+12, OFFSET_CURRENT) < 0)
  480.     {
  481.       /* Seek failed. */
  482.       return;
  483.     }
  484.  
  485.   /* We've made it this far, assume that we have a valid note map file. */
  486.  
  487.   /* Read in entries as long as the ``next'' pointer is not 0. */
  488.   do {
  489.     /* Notemap entry to be read from file. */
  490.     struct NotemapFileEntry entry;
  491.     
  492.     /* Size of storage for the note's name. */
  493.     size_t len;
  494.  
  495.     /* Read the ``next'' pointer and note map entry. */
  496.     if ((*functions->fastread)(file, (UBYTE *)&next, sizeof(next)) < sizeof(next))
  497.       {
  498.     /* Failed to read the correct number of bytes for the ``next'' pointer. */ 
  499.         return;
  500.       }
  501.     if ((*functions->fastread)(file, (UBYTE *)&entry, sizeof(entry)) < sizeof(entry))
  502.       {
  503.     /* Failed to read the correct number of bytes for an entry. */
  504.         return;
  505.       }
  506.  
  507.     /* Store the note name in the note map. */
  508.  
  509.     /* Allocate some memory for the new name. */
  510.     len = strlen(entry.name);
  511.     (*notemap)[entry.note] = (char *)(*functions->myalloc)(len + 1, MEMF_CLEAR);
  512.     if ((*notemap)[entry.note] == (char *)NULL)
  513.       {
  514.     /* Allocation failed. */
  515.         return;
  516.       }
  517.  
  518.     /* Copy the string into the newly allocated memory and null terminate the
  519.        string. */
  520.     strcpy((*notemap)[entry.note], entry.name);
  521.     (*notemap)[entry.note][len] = '\0';
  522.  
  523.   } while (next != 0);
  524.  
  525.   return;
  526. }
  527.  
  528. /* -------------------------------------------------------------------- */
  529. /*            SPLITTING TRACKS                */
  530. /* -------------------------------------------------------------------- */
  531.  
  532. /* For splitting the tracks, I maintain two separate structures, one for
  533.    the note events, and one for the others (i.e. control change, etc.)
  534.    The note events are stored in an array, with each element of the array
  535.    corresponding to a particular MIDI note. The other events are all lumped
  536.    in together. */
  537.  
  538. /* Split a list of events into note events and other events. */
  539. static BOOL
  540. eventlist_split(struct Event *source,    /* Pointer to first event in list */
  541.                                 /* to be split. */
  542.         struct Event **notes,    /* Array of event lists, */
  543.                                 /* one for each MIDI note. */
  544.         struct Event **others)    /* Handle for event list for */
  545.                          /* non-note events. */
  546. {
  547.   struct NoteEvent *event;
  548.  
  549.   /* For each event in the list. */
  550.   for (event = (struct NoteEvent *) source;
  551.        event;
  552.        event = (struct NoteEvent *) event->next)
  553.     {
  554.       /* If it's a MIDI performance event.*/
  555.       if ((event->type & 0xf) == EVENT_VOICE)
  556.         {
  557.       /* Try to allocate a new event and check to see if we succeeded. */
  558.           struct NoteEvent *new = 
  559.         (struct NoteEvent *)(*functions->allocevent)();
  560.           if (new == (struct NoteEvent *) NULL)
  561.             {
  562.           /* Allocation failed. */
  563.               return FALSE;
  564.             }
  565.  
  566.       /* Initialise the new event. */
  567.       *new = *event;
  568.  
  569.       /* Is it a note event? */
  570.           if ((new->status & 0xff) == MIDI_NOTEON)
  571.             {
  572.           new->next = notes[new->value];
  573.           notes[new->value] = new;
  574.             }
  575.           else    /* It's some other sort of MIDI event. */
  576.             {
  577.           new->next = *others;
  578.           *others = new;
  579.             }
  580.         }
  581.     }
  582.  
  583.   return TRUE;
  584. }
  585.  
  586. /* Shameless plug inserted into track notes by the accessory. */
  587. static const char *splitter_notes = "Created by Splitter Accessory";
  588.  
  589. /* Storage for note to name conversion. */
  590. static char name[NOTE_NAME_LEN];
  591.  
  592. /* Returns a text string given a midi note number. */
  593. static char *
  594. note_name(unsigned char note)
  595. {
  596.   static char *note_names[] = {
  597.     "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "Bb", "B"
  598.     };
  599.  
  600.   sprintf(name, "%s%1ld", note_names[note % 12], (int) note / 12);
  601.  
  602.   return name;
  603. }
  604.  
  605. /* Allocate, initialise and return a new track.
  606.    If something goes wrong, returns NULL. */
  607. static struct Track *
  608. track_new(struct Track *old,        /* Track to initialise from. */
  609.       char *name,            /* Name of the new track. */
  610.       unsigned char note,        /* Which MIDI note this corresponds to. */
  611.       struct Event *events)        /* Events for the new track. */
  612.                     /* In reverse order! */
  613. {
  614.   /* Attempt to allocate the track, and check to see if we succeeded. */
  615.   struct Track *track =
  616.     (struct Track *)(*functions->createtrack)(1, 0);
  617.   if (track == (struct Track *) NULL)
  618.     {
  619.       return (struct Track *) NULL;
  620.     }
  621.  
  622.   /* Initialise the track from the fields of the supplied track. */
  623.   track->next = (struct Track *) NULL;
  624.  
  625.   /* Keep the same channel in and out assignments. */
  626.   track->channelin = old->channelin;
  627.   track->channelout = old->channelout;
  628.  
  629.   /* Careful! createtrack() has already given the track a name. */
  630.   (*functions->replacestring)(&(track->clip.name),
  631.                   name ? name : note_name(note));
  632.   track->clip.notes =
  633.     (struct String *)(*functions->allocstring)(splitter_notes);
  634.  
  635.   /* Highest and lowest notes for the clip are the same as the note. */
  636.   track->clip.highnote = note;
  637.   track->clip.lownote = note;
  638.  
  639.   /* Begin and end times. */
  640.   track->clip.begin = 0;
  641.   track->clip.end = events == (struct Event *) NULL ? 0 : events->time;
  642.  
  643.   /* Sort and add the events. */
  644.   track->clip.events.first = 
  645.     (struct Event *)(*functions->sorteventlist)(events);
  646.   track->clip.events.point = (struct Event *) NULL;
  647.  
  648.   return track;
  649. }
  650.  
  651. /* Split a track according to the supplied notemap. It will add as many
  652.    tracks as needed following the selected track. */
  653. static void
  654. track_split(struct Track *track,    /* Track to be split. */
  655.         Notemap *notemap)        /* Note map to use. */
  656. {
  657.   int i;
  658.  
  659.   /* List of events for non-note MIDI events. */
  660.   struct Event *others = (struct Event *) NULL;
  661.  
  662.   /* Array of lists of events, one for each MIDI note. */
  663.   struct Event *notes[MIDI_NOTE_NUM];
  664.  
  665.   /* Initialise the event list array. */
  666.   for (i = 0; i < MIDI_NOTE_NUM; i++)
  667.     {
  668.       notes[i] = (struct Event *) NULL;
  669.     }
  670.  
  671.   /* Try to separate out the events in the track. */
  672.   if (eventlist_split(track->clip.events.first, notes, &others))
  673.     {
  674.       /* List of new tracks */
  675.       struct Track *new_tracks = NULL;
  676.  
  677.       register unsigned int i;
  678.       
  679.       /* Were there any non-note events? */
  680.       if (others != (struct Event *) NULL)
  681.     {
  682.       new_tracks = track_new(track, "Other Events",
  683.                  (unsigned char) 0,
  684.                  others);
  685.     }
  686.       
  687.       /* Create tracks for each of the lists of events. */
  688.       for (i = 0; i < MIDI_NOTE_NUM; i++)
  689.     {
  690.       /* If there are notes for the track, notes[i] will be non-null. */
  691.       if (notes[i] != (struct Event *) NULL)
  692.         {
  693.           /* Make the new track. */
  694.           struct Track *new = track_new(track,
  695.                         (*notemap)[i],
  696.                         (unsigned char) i,
  697.                         notes[i]);
  698.           
  699.           /* Stick it at the start of the list so far. */
  700.           new->next = new_tracks;
  701.           new_tracks = new;
  702.         }
  703.     }
  704.       
  705.       /* Splice in the list of new tracks. */
  706.       track->next = (struct Track *)(*functions->List_Cat)(new_tracks, track->next);
  707.     }
  708. }
  709.  
  710. /* -------------------------------------------------------------------- */
  711. /*                INTERFACE                */
  712. /* -------------------------------------------------------------------- */
  713.  
  714. /* I built this interface by hand as well. Does anyone have a favorite
  715.    GUI builder? */
  716.  
  717. static const struct IntuiText itext1 = {
  718.   4,0,JAM1,
  719.   12,1,
  720.   NULL,
  721.   "Load Note Map File",
  722.   NULL
  723. };
  724.  
  725. static const struct Gadget gadget1 = {
  726.   NULL,
  727.   15, 16,
  728.   168, 9,
  729.   (ULONG) NULL,
  730.   RELVERIFY+GADGIMMEDIATE,
  731.   BOOLGADGET,
  732.   NULL,
  733.   NULL,
  734.   &itext1,
  735.   (ULONG) NULL,
  736.   NULL,
  737.   1,
  738.   NULL
  739. };
  740.  
  741. static const struct IntuiText itext2 = {
  742.   4,0,JAM1,
  743.   4,1,
  744.   NULL,
  745.   "Split Selected Track",
  746.   NULL
  747. };
  748.  
  749. static const struct Gadget gadget2 = {
  750.   &gadget1,
  751.   15, 27,
  752.   168, 9,
  753.   (ULONG) NULL,
  754.   RELVERIFY+GADGIMMEDIATE,
  755.   BOOLGADGET,
  756.   NULL,
  757.   NULL,
  758.   &itext2,
  759.   (ULONG) NULL,
  760.   NULL,
  761.   2,
  762.   NULL
  763. };
  764.  
  765. static const struct IntuiText itext3 = {
  766.   4,0,JAM1,
  767.   28, 1,
  768.   NULL,
  769.   "Clear Notemap",
  770.   NULL
  771. };
  772.  
  773. static const struct Gadget gadget3 = {
  774.   &gadget2,
  775.   15, 38,
  776.   168, 9,
  777.   (ULONG) NULL,
  778.   RELVERIFY+GADGIMMEDIATE,
  779.   BOOLGADGET,
  780.   NULL,
  781.   NULL,
  782.   &itext3,
  783.   (ULONG) NULL,
  784.   NULL,
  785.   3,
  786.   NULL
  787. };
  788.  
  789. /* Start of gadget list. */
  790. #define gadget_list (&gadget3)
  791.  
  792. /* Close the splitter window. */
  793. __geta4                /* Callback function. */
  794. splitter_close(void)
  795. {
  796.   /* Ensure that we have something to close. */
  797.   if (splitter.accessory.window)
  798.   {
  799.     struct IntuiMessage *message;
  800.  
  801.     (*functions->EmbossOff)(splitter.accessory.window,1);
  802.     (*functions->EmbossOff)(splitter.accessory.window,2);
  803.     (*functions->EmbossOff)(splitter.accessory.window,3);
  804.     (*functions->EmbossWindowOff)(splitter.accessory.window);
  805.  
  806.     /* Remember where we were in case we're reopened later. */
  807.     splitter.accessory.left = splitter.accessory.window->LeftEdge;
  808.     splitter.accessory.top = splitter.accessory.window->TopEdge;
  809.  
  810.     /* Make it hard to send us messages and eat up any that are pending. */
  811.     splitter.accessory.window->UserPort = 0;
  812.     ModifyIDCMP(splitter.accessory.window,0);
  813.     WaitTOF();
  814.     WaitTOF();
  815.     WaitTOF();
  816.     WaitTOF();
  817.     WaitTOF();
  818.     Forbid();
  819.     while (message = (struct IntuiMessage *)GetMsg(functions->window->UserPort))
  820.       {
  821.         ReplyMsg((struct Message *)message);
  822.       }
  823.     (*functions->FlashyCloseWindow)(splitter.accessory.window);
  824.     splitter.accessory.window = NULL;
  825.     Permit();
  826.   }
  827.  
  828.   return(1);
  829. }
  830.  
  831. static const char *title = "Splitter v1.0";
  832.  
  833. /* Open the splitter window. */
  834. __geta4                /* Callback function. */
  835. splitter_open(void)
  836. {
  837.   /* Use v37+ style window tags to specify the new window. */
  838.   const struct TagItem tags[] = {
  839.     {WA_Left, splitter.accessory.left},
  840.     {WA_Top, splitter.accessory.top},
  841.     {WA_Width, 198},
  842.     {WA_Height, 53},
  843.     {WA_DetailPen, 5},
  844.     {WA_BlockPen, 1},
  845.     {WA_IDCMP, GADGETUP|CLOSEWINDOW},
  846.     {WA_DragBar, FALSE},
  847.     {WA_DepthGadget, FALSE},
  848.     {WA_CloseGadget, FALSE},
  849.     {WA_Activate, TRUE},
  850.     {WA_NoCareRefresh, TRUE},
  851.     {WA_Borderless, TRUE},
  852.     {WA_Gadgets, (ULONG) gadget_list},
  853.     {WA_Checkmark, (ULONG) NULL},
  854.     {WA_Title, (ULONG) NULL},
  855.     {WA_ScreenTitle, (ULONG) title},
  856.     {WA_CustomScreen, (ULONG) functions->screen}
  857.   };
  858.  
  859.   /* Attempt to open the window, and check to see if we were successful. */
  860.   splitter.accessory.window = (struct Window *)OpenWindowTagList(NULL, &tags);
  861.   if (splitter.accessory.window != (struct Window *) NULL)
  862.   {
  863.     /* Set up communication. */
  864.     splitter.accessory.window->UserPort = functions->window->UserPort;
  865.     ModifyIDCMP(splitter.accessory.window,functions->window->IDCMPFlags);
  866.  
  867.     (*functions->EmbossWindowOn)(splitter.accessory.window,
  868.                  WINDOWCLOSE|WINDOWDEPTH|WINDOWDRAG,
  869.                      "Splitter",(short)-1,(short)-1,0,0);
  870.     (*functions->EmbossOn)(splitter.accessory.window,1,1);
  871.     (*functions->EmbossOn)(splitter.accessory.window,2,1);
  872.     (*functions->EmbossOn)(splitter.accessory.window,3,1);
  873.   }
  874.  
  875.   return((long)splitter.accessory.window);
  876. }
  877.  
  878. /* Gather and process user input from the splitter window. */
  879. __geta4                /* Callback function. */
  880. splitter_edit(struct IntuiMessage *message)    /* Message to process. */
  881. {
  882.   struct Window *window = message->IDCMPWindow;
  883.   struct Gadget *gadget;
  884.   long class,code;
  885.  
  886.   class = message->Class;
  887.   code = message->Code;
  888.   gadget = (struct Gadget *) message->IAddress;
  889.   ReplyMsg((struct Message *)message);
  890.   class = (*functions->SystemGadgets)(window,class,gadget,code);
  891.  
  892.   if (class == CLOSEWINDOW)
  893.     {
  894.       (void) splitter_close();
  895.       return 0;
  896.     }
  897.   else if (class == GADGETUP)
  898.     {
  899.       switch (gadget->GadgetID)
  900.         {
  901.     case 1:    /* Load Note Map File */
  902.       {
  903.         char filename[255];
  904.         
  905.         /* Get the filename */
  906.         (*functions->FileName)(filename,"Load Note Map File:","drummap",
  907.                    functions->screen,
  908.                    FILES_OPEN|FILES_DELETE|FILES_TYPE,0,0);
  909.         if (filename[0])
  910.           {
  911.         /* Attempt to open the file and check to see if we
  912.            succeeded. */
  913.         long file = (*functions->fastopen)(filename,MODE_OLDFILE);
  914.         if (file)
  915.           {
  916.             if ((*functions->areyousure)("replace the note map?"))
  917.               {
  918.             (*functions->openwait)();
  919.                         notemap_delete_entries(splitter.notemap);
  920.                         notemap_load(file, splitter.notemap);
  921.             (*functions->closewait)();
  922.               }
  923.             (*functions->fastclose)(file);
  924.           }
  925.         else
  926.           {
  927.             accessory_error(splitter.accessory.window,
  928.                     "Couldn't open file for reading");
  929.           }
  930.           }
  931.       }
  932.           break;
  933.     case 2:    /* Split Selected Track */
  934.       {
  935.         if (functions->groupid != 0)    /* Group selected? */
  936.           {
  937.         accessory_error(splitter.accessory.window,
  938.                 "Can't split a group");
  939.           }  
  940.         else if (functions->selectedtrack)    /* Track selected? */
  941.           {
  942.         (*functions->openwait)();
  943.         track_split(functions->selectedtrack, splitter.notemap);
  944.         (*functions->display)(0x1000000);
  945.         (*functions->closewait)();
  946.           }
  947.         else /* No track selected. */
  948.           {
  949.         accessory_error(splitter.accessory.window,
  950.                 "You must select a track for splitting");
  951.           }
  952.       }
  953.           break;
  954.     case 3:
  955.       {
  956.         if ((*functions->areyousure)("clear the note map?"))
  957.           {
  958.         (*functions->openwait)();
  959.         notemap_delete_entries(splitter.notemap);
  960.         (*functions->closewait)();
  961.           }
  962.       }
  963.     }
  964.     }
  965.   return 1;
  966. }
  967.  
  968. /* Free the notemap. */
  969. __geta4                /* Callback function. */
  970. splitter_remove(void)
  971. {
  972.   notemap_delete(splitter.notemap);
  973. }
  974.  
  975. struct Accessory *
  976. inittoolmaster(void)
  977. {
  978.   memset((char *)&splitter,0,sizeof(struct Splitter));
  979.   splitter.accessory.left = INITIAL_LEFT;
  980.   splitter.accessory.top = INITIAL_TOP;
  981.   splitter.accessory.id = MAKE_IDS("SPLT");
  982.   splitter.accessory.next = 0;
  983.   splitter.accessory.image = &splitter_image;
  984.   splitter.accessory.onimage = &splitter_onimage;
  985.   splitter.accessory.open = splitter_open;
  986.   splitter.accessory.close = splitter_close;
  987.   splitter.accessory.edit = (no_prototype) splitter_edit;
  988.   splitter.accessory.remove = splitter_remove;
  989.   strcpy(splitter.accessory.name, "Splitter");
  990.   splitter.notemap = notemap_new();
  991.   if (splitter.notemap == (struct Notemap *) NULL)
  992.     {
  993.       return (struct Accessory *) NULL;
  994.     }
  995.   
  996.   return(&splitter.accessory);
  997. }
  998.